using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Windows.Forms;

namespace MKDS_Course_Editor
{
    class nsbmd2
    {
        string BMD0 = "";
        byte[] magic;
        Int32 nFileSize = 0;
        Int16 nSize = 0;
        Int16 nBlock = 0;
        Int32 MDL0offset = 0;
        Int32 TEX0offset = 0;

        string MDL0 = "";
        Int32 blockSize = 0;
        sbyte nmodel = 0;
        Int16 headersize = 0;
        string[] modelname;
        Int32 model1size = 0;
        Int32 AMD = 0;
        Int32 TPO = 0;
        Int32 BDL = 0;
        Int32 EDL = 0;
        SByte nObjects = 0;
        SByte nMaterials = 0;
        SByte nPolygons = 0;
        Int16 nvertices = 0;
        Int16 npoly = 0;
        Int16 ntriangles = 0;
        Int16 nquats = 0;
        Int16 BBoxX = 0;
        Int16 BBoxY = 0;
        Int16 BBoxZ = 0;
        Int16 BBoxW = 0;
        Int16 BBoxH = 0;
        Int16 BBoxD = 0;
        Int32 RTUData = 0;
        Int32 RTUData2 = 0;

        sbyte nobj = 0;
        Int16 headersize2 = 0;
        string[] objname;
        Int16 TransformFlag = 0;
        Int16 Unknown = 0;
        int t;
        int r;
        int s;
        int p;
        int pv;
        int neg;
        int unknown1;
        int[] polygon;
        int[] material;
        int[] model1;
        Int16 OTS = 0;
        Int16 OPS = 0;
        sbyte nmat = 0;
        Int16 headersize3 = 0;
        string[] matname;
        sbyte ntex = 0;
        Int16 headersize4 = 0;
        string[] texname;
        sbyte npal = 0;
        Int16 headersize5 = 0;
        string[] palname;
        sbyte npol = 0;
        Int16 headersize6 = 0;
        string[] polname;

        static int stackID;
        public SharpGL.SceneGraph.Scene load(string file, SharpGL.SceneGraph.Scene g)
        {
            EndianBinaryReader er = new EndianBinaryReader(File.OpenRead(file), Endianness.LittleEndian);
            BMD0 = er.ReadString(Encoding.ASCII, 4);
            magic = er.ReadBytes(4);
            nFileSize = er.ReadInt32();
            nSize = er.ReadInt16();
            nBlock = er.ReadInt16();
            MDL0offset = er.ReadInt32();
            if (er.BaseStream.Position != MDL0offset)
            {
                TEX0offset = er.ReadInt32();
            }

            MDL0 = er.ReadString(Encoding.ASCII, 4);
            blockSize = er.ReadInt32();
            er.ReadByte();
            nmodel = er.ReadSByte();
            headersize = er.ReadInt16();
            er.ReadBytes(8);
            modelname = new string[nmodel];
            for (int i = 0; i < nmodel; i++)
            {
                er.ReadBytes(4);
            }
            er.ReadBytes(4);
            model1 = new int[nmodel];
            for (int i = 0; i < nmodel; i++)
            {
                model1[i] = er.ReadInt32();
            }
            for (int i = 0; i < nmodel; i++)
            {
                modelname[i] = er.ReadString(Encoding.ASCII, 16);
                modelname[i] = modelname[i].Replace(Convert.ToString(Convert.ToChar(0x00)), "");
                MessageBox.Show(modelname[i]);
            }
            model1size = er.ReadInt32();
            AMD = er.ReadInt32();
            TPO = er.ReadInt32();
            BDL = er.ReadInt32();
            EDL = er.ReadInt32();
            er.ReadBytes(3);
            nObjects = er.ReadSByte();
            nMaterials = er.ReadSByte();
            nPolygons = er.ReadSByte();
            er.ReadBytes(10);
            nvertices = er.ReadInt16();
            npoly = er.ReadInt16();
            ntriangles = er.ReadInt16();
            nquats = er.ReadInt16();
            BBoxX = er.ReadInt16();
            BBoxY = er.ReadInt16();
            BBoxZ = er.ReadInt16();
            BBoxW = er.ReadInt16();
            BBoxH = er.ReadInt16();
            BBoxD = er.ReadInt16();
            RTUData = er.ReadInt32();
            RTUData2 = er.ReadInt32();
            //object header
            er.ReadByte();
            nobj = er.ReadSByte();
            headersize2 = er.ReadInt16();
            er.ReadBytes(8);
            for (int i = 0; i < nobj; i++)
            {
                er.ReadBytes(4);
            }
            er.ReadBytes(4);
            for (int i = 0; i < nobj; i++)
            {
                er.ReadBytes(4);
            }
            objname = new string[nobj];
            for (int i = 0; i < nobj; i++)
            {
                objname[i] = er.ReadString(Encoding.ASCII, 16);
                objname[i] = objname[i].Replace(Convert.ToString(Convert.ToChar(0x00)), "");
                MessageBox.Show(objname[i]);
            }
            TransformFlag = er.ReadInt16();
            Unknown = er.ReadInt16();
            t = TransformFlag >> 0 & 1;
            r = TransformFlag >> 1 & 1;
            s = TransformFlag >> 2 & 1;
            p = TransformFlag >> 3 & 1;
            pv = TransformFlag >> 4 & 0xf;
            neg = TransformFlag >> 8 & 0xf;
            unknown1 = TransformFlag >> 12 & 0xf;
            er.BaseStream.Position = (TPO + model1[0] + nSize + 4);
            OTS = er.ReadInt16();
            OPS = er.ReadInt16();

            er.ReadByte();
            nmat = er.ReadSByte();
            headersize3 = er.ReadInt16();
            er.ReadBytes(8);
            for (int i = 0; i < nmat; i++)
            {
                er.ReadBytes(4);
            }
            er.ReadBytes(4);
            for (int i = 0; i < nmat; i++)
            {
                er.ReadBytes(4);
            }
            matname = new string[nmat];
            for (int i = 0; i < nmat; i++)
            {
                matname[i] = er.ReadString(Encoding.ASCII, 16);
                matname[i] = matname[i].Replace(Convert.ToString(Convert.ToChar(0x00)), "");
                MessageBox.Show(matname[i]);
            }

            er.ReadByte();
            ntex = er.ReadSByte();
            headersize4 = er.ReadInt16();
            er.ReadBytes(8);
            for (int i = 0; i < ntex; i++)
            {
                er.ReadBytes(4);
            }
            er.ReadBytes(4);
            for (int i = 0; i < ntex; i++)
            {
                er.ReadBytes(4);
            }
            texname = new string[ntex];
            for (int i = 0; i < ntex; i++)
            {
                texname[i] = er.ReadString(Encoding.ASCII, 16);
                texname[i] = texname[i].Replace(Convert.ToString(Convert.ToChar(0x00)), "");
                MessageBox.Show(texname[i]);
            }

            er.ReadByte();
            npal = er.ReadSByte();
            headersize5 = er.ReadInt16();
            er.ReadBytes(8);
            for (int i = 0; i < npal; i++)
            {
                er.ReadBytes(4);
            }
            er.ReadBytes(4);
            for (int i = 0; i < npal; i++)
            {
                er.ReadBytes(4);
            }
            palname = new string[npal];
            for (int i = 0; i < npal; i++)
            {
                palname[i] = er.ReadString(Encoding.ASCII, 16);
                palname[i] = palname[i].Replace(Convert.ToString(Convert.ToChar(0x00)), "");
                MessageBox.Show(palname[i]);
            }

            for (int i = 0; i < npal; i++)
            {
                er.ReadBytes(48);
            }

            er.ReadByte();
            npol = er.ReadSByte();
            headersize6 = er.ReadInt16();
            er.ReadBytes(8);
            for (int i = 0; i < npol; i++)
            {
                er.ReadBytes(4);
            }
            er.ReadBytes(4);
            for (int i = 0; i < npol; i++)
            {
                er.ReadBytes(4);
            }
            polname = new string[npol];
            for (int i = 0; i < npol; i++)
            {
                polname[i] = er.ReadString(Encoding.ASCII, 16);
                polname[i] = polname[i].Replace(Convert.ToString(Convert.ToChar(0x00)), "");
                MessageBox.Show(polname[i]);
            }

            for (int i = 0; i < npol; i++)
            {
                er.ReadBytes(16);
            }
            g.ClearColor = System.Drawing.Color.Orange;
            g.DrawExtras = true;
            SharpGL.SceneGraph.Polygon p0p = new SharpGL.SceneGraph.Polygon();
            while (!(er.BaseStream.Position <= er.BaseStream.Length)) //|| er.ReadString(Encoding.ASCII, 4) == "TEX0")
            {
                //er.BaseStream.Position -= 4;
                int mode;
                float[] vtx_state = { 0.0f, 0.0f, 0.0f };
                float[] vtx_trans = { 0.0f, 0.0f, 0.0f };
                byte[] b = er.ReadBytes(4);
                
                
                for (int i = 0; i < 4; i++)
                {
                    switch (b[i])
                    {
                        case 0:		// No Operation (for padding packed GXFIFO commands)
                            break;
                        case 0x14:
                            /*
                              MTX_RESTORE - Restore Current Matrix from Stack (W)
                              Sets C=[N]. The stack pointer S is not used, and is left unchanged.
                              Parameter Bit0-4:  Stack Address (0..30) (31 causes overflow in GXSTAT.15)
                              Parameter Bit5-31: Not used
                            */
                            {

                                stackID = er.ReadInt32();

                                //memcpy( &CurrentMatrix, &MatrixStack[stackID], sizeof( MTX44 ) );
                                er.ReadBytes(4);
                                break;
                            }
                        case 0x1b:
                            /*
                              MTX_SCALE - Multiply Current Matrix by Scale Matrix (W)
                              Sets C=M*C. Parameters: 3, m[0..2] (MTX_SCALE doesn't change Vector Matrix)
                            */
                            {
                                int x, y, z;
                                x = er.ReadInt32();
                                y = er.ReadInt32();
                                z = er.ReadInt32();
                                g.OpenGL.Scale(x / 4096, y / 4096, z / 4096);
                                //mtx_Scale( &CurrentMatrix, ((float)x) / 4096.0f, ((float)y) / 4096.0f, ((float)z) / 4096.0f );
                                break;
                            }
                        case 0x20:	// Directly Set Vertex Color (W)
                            {
                                int rgb, r1, g1, b1;

                                rgb = er.ReadInt32();

                                //if ( gOptColoring ) {
                                r1 = (rgb >> 0) & 0x1F;
                                g1 = (rgb >> 5) & 0x1F;
                                b1 = (rgb >> 10) & 0x1F;
                                g.OpenGL.Color(r1 / 31, g1 / 31, b1 / 31);
                                //glColor3f( ((float)r)/31.0f, ((float)g)/31.0f, ((float)b)/31.0f );
                                //}
                                break;
                            }
                        case 0x21:
                            /*
                              Set Normal Vector (W)
                              0-9   X-Component of Normal Vector (1bit sign + 9bit fractional part)
                              10-19 Y-Component of Normal Vector (1bit sign + 9bit fractional part)
                              20-29 Z-Component of Normal Vector (1bit sign + 9bit fractional part)
                              30-31 Not used
                            */
                            {
                                int xyz, x, y, z;

                                xyz = er.ReadInt32();


                                x = (xyz >> 0) & 0x3FF;	//if( x & 0x200 )		x |= 0xFFFFFC00;
                                y = (xyz >> 10) & 0x3FF;	//if( y & 0x200 )		y |= 0xFFFFFC00;
                                z = (xyz >> 20) & 0x3FF;	//if( z & 0x200 )		z |= 0xFFFFFC00;
                                g.OpenGL.Normal3i(x / 512, y / 512, z / 512);
                                
                                //glNormal3f( ((float)x)/512.0f, ((float)y)/512.0f, ((float)z)/512.0f );
                                break;
                            }
                        case 0x22:
                            /*
                              Set Texture Coordinates (W)
                              Parameter 1, Bit 0-15   S-Coordinate (X-Coordinate in Texture Source)
                              Parameter 1, Bit 16-31  T-Coordinate (Y-Coordinate in Texture Source)
                              Both values are 1bit sign + 11bit integer + 4bit fractional part.
                              A value of 1.0 (=1 SHL 4) equals to one Texel.
                            */
                            {
                                int st, s2, t2;

                                st = er.ReadInt32();
                                //commandptr += 4;

                                s2 = (st >> 0) & 0xffff;	//if ( s2 & 0x8000 ) s2 |= 0xffff0000;
                                t2 = (st >> 16) & 0xffff;	//if ( t2 & 0x8000 ) t2 |= 0xffff0000;
                                //glTexCoord2f( ((float)s2)/16.0f, ((float)t2)/16.0f );
                                g.OpenGL.TexCoord2f(s2 / 16, t2 / 16);
                                
                                break;
                            }
                        case 0x23:
                            /*
                              VTX_16 - Set Vertex XYZ Coordinates (W)
                              Parameter 1, Bit 0-15   X-Coordinate (signed, with 12bit fractional part)
                              Parameter 1, Bit 16-31  Y-Coordinate (signed, with 12bit fractional part)
                              Parameter 2, Bit 0-15   Z-Coordinate (signed, with 12bit fractional part)
                              Parameter 2, Bit 16-31  Not used
                            */
                            {
                                int parameter, x, y, z;

                                parameter = er.ReadInt32();


                                x = (parameter >> 0) & 0xFFFF;	//if( x & 0x8000 )	x |= 0xFFFF0000;
                                y = (parameter >> 16) & 0xFFFF;	//if( y & 0x8000 )	y |= 0xFFFF0000;

                                parameter = er.ReadInt32();

                                z = parameter & 0xFFFF; //if (z & 0x8000)  z |= 0xFFFF0000; 

                                vtx_state[0] = ((float)x) / 4096.0f;
                                vtx_state[1] = ((float)y) / 4096.0f;
                                vtx_state[2] = ((float)z) / 4096.0f;
                                if (stackID != -1)
                                {
                                    //if ( g_anim ) 
                                    //	;
                                    //else

                                    //	mtx_MultVector( vtx_trans, &CurrentMatrix, vtx_state );

                                    g.OpenGL.Vertex3i((int)vtx_trans[0], (int)vtx_trans[1], (int)vtx_trans[2]);
                                    
                                    //glVertex3fv( vtx_trans );
                                }
                                else
                                {
                                    g.OpenGL.Vertex3i((int)vtx_state[0], (int)vtx_state[1], (int)vtx_state[2]);
                                    //glVertex3fv( vtx_state );
                                }

                                break;
                            }
                        case 0x24:
                            /*
                              VTX_10 - Set Vertex XYZ Coordinates (W)
                              Parameter 1, Bit 0-9    X-Coordinate (signed, with 6bit fractional part)
                              Parameter 1, Bit 10-19  Y-Coordinate (signed, with 6bit fractional part)
                              Parameter 1, Bit 20-29  Z-Coordinate (signed, with 6bit fractional part)
                              Parameter 1, Bit 30-31  Not used
                            */
                            {
                                int xyz, x, y, z;

                                xyz = er.ReadInt32();


                                x = (xyz >> 0) & 0x3FF;	//if( x & 0x200 )	x |= 0xFFFFFC00;
                                y = (xyz >> 10) & 0x3FF;	//if( y & 0x200 )	y |= 0xFFFFFC00;
                                z = (xyz >> 20) & 0x3FF;	//if( z & 0x200 )	z |= 0xFFFFFC00;

                                vtx_state[0] = ((float)x) / 64.0f;
                                vtx_state[1] = ((float)y) / 64.0f;
                                vtx_state[2] = ((float)z) / 64.0f;

                                if (stackID != -1)
                                {

                                    //mtx_MultVector( vtx_trans, &CurrentMatrix, vtx_state );
                                    g.OpenGL.Vertex3i((int)vtx_trans[0], (int)vtx_trans[1], (int)vtx_trans[2]);
                                }
                                else
                                {
                                    g.OpenGL.Vertex3i((int)vtx_state[0], (int)vtx_state[1], (int)vtx_state[2]);
                                }
                                break;
                            }
                        case 0x25:
                            /*
                              VTX_XY - Set Vertex XY Coordinates (W)
                              Parameter 1, Bit 0-15   X-Coordinate (signed, with 12bit fractional part)
                              Parameter 1, Bit 16-31  Y-Coordinate (signed, with 12bit fractional part)
                            */
                            {
                                int xy, x, y;

                                xy = er.ReadInt32();


                                x = (xy >> 0) & 0xFFFF;	//if ( x & 0x8000 )	x |= 0xFFFF0000;
                                y = (xy >> 16) & 0xFFFF;	//if ( y & 0x8000 )	y |= 0xFFFF0000;

                                vtx_state[0] = ((float)x) / 4096.0f;
                                vtx_state[1] = ((float)y) / 4096.0f;

                                if (stackID != -1)
                                {
                                    //mtx_MultVector( vtx_trans, &CurrentMatrix, vtx_state );
                                    g.OpenGL.Vertex3i((int)vtx_trans[0], (int)vtx_trans[1], (int)vtx_trans[2]);
                                }
                                else
                                {
                                    g.OpenGL.Vertex3i((int)vtx_state[0], (int)vtx_state[1], (int)vtx_state[2]);
                                }
                                break;
                            }
                        case 0x26:
                            /*
                              VTX_XZ - Set Vertex XZ Coordinates (W)
                              Parameter 1, Bit 0-15   X-Coordinate (signed, with 12bit fractional part)
                              Parameter 1, Bit 16-31  Z-Coordinate (signed, with 12bit fractional part)
                            */
                            {
                                int xz, x, z;

                                xz = er.ReadInt32();


                                x = (xz >> 0) & 0xFFFF;	//if ( x & 0x8000 )	x |= 0xFFFF0000;
                                z = (xz >> 16) & 0xFFFF;	//if ( z & 0x8000 )	z |= 0xFFFF0000;

                                vtx_state[0] = ((float)x) / 4096.0f;
                                vtx_state[2] = ((float)z) / 4096.0f;

                                if (stackID != -1)
                                {
                                    //mtx_MultVector( vtx_trans, &CurrentMatrix, vtx_state );
                                    g.OpenGL.Vertex3i((int)vtx_trans[0], (int)vtx_trans[1], (int)vtx_trans[2]);
                                }
                                else
                                {
                                    g.OpenGL.Vertex3i((int)vtx_state[0], (int)vtx_state[1], (int)vtx_state[2]);
                                }
                                break;
                            }
                        case 0x27:
                            /*
                              VTX_YZ - Set Vertex YZ Coordinates (W)
                              Parameter 1, Bit 0-15   Y-Coordinate (signed, with 12bit fractional part)
                              Parameter 1, Bit 16-31  Z-Coordinate (signed, with 12bit fractional part)
                            */
                            {
                                int yz, y, z;
                                yz = er.ReadInt32();


                                y = (yz >> 0) & 0xFFFF;	//if( y & 0x8000 )	y |= 0xFFFF0000;
                                z = (yz >> 16) & 0xFFFF;	//if( z & 0x8000 )	z |= 0xFFFF0000;

                                vtx_state[1] = ((float)y) / 4096.0f;
                                vtx_state[2] = ((float)z) / 4096.0f;

                                if (stackID != -1)
                                {
                                    //mtx_MultVector( vtx_trans, &CurrentMatrix, vtx_state );
                                    g.OpenGL.Vertex3i((int)vtx_trans[0], (int)vtx_trans[1], (int)vtx_trans[2]);
                                }
                                else
                                {
                                    g.OpenGL.Vertex3i((int)vtx_state[0], (int)vtx_state[1], (int)vtx_state[2]);
                                }
                                break;
                            }
                        case 0x28:
                            /*
                              VTX_DIFF - Set Relative Vertex Coordinates (W)
                              Parameter 1, Bit 0-9    X-Difference (signed, with 9bit fractional part)
                              Parameter 1, Bit 10-19  Y-Difference (signed, with 9bit fractional part)
                              Parameter 1, Bit 20-29  Z-Difference (signed, with 9bit fractional part)
                              Parameter 1, Bit 30-31  Not used
                            */
                            {
                                int xyz, x, y, z;
                                xyz = er.ReadInt32();


                                x = (xyz >> 0) & 0x3FF;	//if ( x & 0x200 )	x |= 0xFFFFFC00;
                                y = (xyz >> 10) & 0x3FF;	//if ( y & 0x200 )	y |= 0xFFFFFC00;
                                z = (xyz >> 20) & 0x3FF;	//if ( z & 0x200 )	z |= 0xFFFFFC00;

                                vtx_state[0] += ((float)x) / 4096.0f;
                                vtx_state[1] += ((float)y) / 4096.0f;
                                vtx_state[2] += ((float)z) / 4096.0f;

                                if (stackID != -1)
                                {
                                    //mtx_MultVector( vtx_trans, &CurrentMatrix, vtx_state );
                                    g.OpenGL.Vertex3i((int)vtx_trans[0], (int)vtx_trans[1], (int)vtx_trans[2]);
                                }
                                else
                                {
                                    g.OpenGL.Vertex3i((int)vtx_state[0], (int)vtx_state[1], (int)vtx_state[2]);
                                }
                                break;
                            }
                        case 0x40:	// Start of Vertex List (W)
                            {
                                mode = er.ReadInt32();


                                switch (mode)
                                {
                                    case 0: mode = (int)OpenTK.Graphics.OpenGL.BeginMode.Triangles; break;
                                    case 1: mode = (int)OpenTK.Graphics.OpenGL.BeginMode.Quads; break;
                                    case 2: mode = (int)OpenTK.Graphics.OpenGL.BeginMode.TriangleStrip; break;
                                    case 3: mode = (int)OpenTK.Graphics.OpenGL.BeginMode.QuadStrip; break;
                                    default: break;
                                }
                                g.OpenGL.Begin((uint)mode);
                                //glBegin( mode );
                                break;
                            }
                        case 0x41:	// End of Vertex List (W)
                            //glEnd();

                            g.OpenGL.End();
                            // for vertex mode, display at maximum certain number of vertex-list
                            // decrease cur_vertex so that when we reach 0, stop rendering any further

                            //cur_vertex--;
                            //if ( cur_vertex < 0 && gOptVertexMode ) return TRUE;
                            break;
                        default:
                            //assert(0);

                            break;

                    }

                }
            }
            return g;

        }
    }
}
